package com.yugao.fintech.framework.database.flyway;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.Flyway;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 支持同时flyway分组处理, 需求如下 <br/>
 * <p>
 * 我希望脚本是按照业务模块划分, 每个业务模块目录下的sql脚本版本都是独立的, 每个业务模块单独生成flyway版本控制表, 资源目录格式如下
 *
 * <pre class="code">
 * resources
 *   db
 *      order
 *          V1.0.0__init.sql
 *          V1.0.1__create.sql
 *      user
 *          V1.0.0__init.sql
 *          V1.0.1__create.sql </pre>
 * <p/>
 *
 * @apiNote 需要配置draper-starter-dynamic-datasource依赖使用, 否则不会生效, 且需要在不同的数据库中
 */
@Slf4j
@Configuration
@RequiredArgsConstructor
@ConditionalOnClass({FlywayAutoConfiguration.class, DynamicRoutingDataSource.class})
public class MyFlywayConfig {
    private final MyFlywayProperties flywayProperties;

    private final DataSource dataSource;

    @PostConstruct
    public void migrateSql() {
        log.info("正在执行 flyway migrate Sql, dataSource: {}", dataSource.getClass().getName());
        List<MyFlywayProperties.Properties> flyways = flywayProperties.getFlyways();
        // 校验是否有重复的table名字
        Map<String, List<MyFlywayProperties.Properties>> groupMap =
                flyways.stream().collect(Collectors.groupingBy(MyFlywayProperties.Properties::getTable));
        groupMap.forEach((k, v) -> {
            if (Objects.nonNull(v) && v.size() > 1) {
                throw new RuntimeException("flyway table " + k + " is repeat");
            }
        });
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;

        for (MyFlywayProperties.Properties item : flyways) {
            if (!item.isEnabled()) {
                continue;
            }
            Flyway flyway = Flyway.configure()
                    .dataSource(ds.getDataSource(item.getDataSource()))
                    .locations(item.getLocations().toArray(new String[]{}))
                    .baselineOnMigrate(item.getBaselineOnMigrate())
                    .table(item.getTable())
                    .outOfOrder(item.getOutOfOrder())
                    .validateOnMigrate(item.getValidateOnMigrate())
                    .baselineVersion(item.getBaselineVersion())
                    .baselineVersion(item.getBaselineVersion())
                    .encoding(item.getEncoding())
                    .validateOnMigrate(item.getValidateOnMigrate())
                    .cleanDisabled(item.getCleanDisabled())
                    .load();
            flyway.migrate();
            log.info("flyway migrate, table: {}", item.getTable());
        }
    }
}
